Repository navigation
Fix purify stopping before the tensor is pure with a random order - #708
Open
Aditya-Pathanjali wants to merge 1 commit into
Open
Aditya-Pathanjali wants to merge 1 commit into
Aditya-Pathanjali wants to merge 1 commit into
Conversation
Purify visits the surfaces in a new random order on every sweep and stopped at the first sweep whose total impurity did not shrink compared to the previous sweep. With a random order that total is not monotone, and empty cells make convergence slow, so tensors with empty cells were often left impure without any error. With is_randomized=False the same inputs were purified to about 1e-16. When the order is random, a sweep that fails to shrink the total now only ends the loop once the total has dropped to floating point noise relative to the first sweep (1e-12). Otherwise the loop continues until 20 sweeps in a row fail to set a new minimum, which also guarantees that it terminates. The fixed-order path is unchanged. The same exit condition in the multiclass loop gets the same treatment. On 5x6 tensors with 60% empty cells, 92 of 100 results were impure before and none are after, with a worst row and column sum of about 1e-11. Inputs that already purified correctly take the same number of sweeps as before. Fixes interpretml#702 Signed-off-by: Aditya-Pathanjali <pathanjaliaditya1708@gmail.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #708 +/- ##
==========================================
- Coverage 67.80% 67.77% -0.04%
==========================================
Files 77 77
Lines 11893 11893
==========================================
- Hits 8064 8060 -4
- Misses 3829 3833 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #702
purifyvisits the surfaces in a new random order on every sweep and stopped at the first sweep whose total impurity did not shrink compared to the previous sweep. With a random order that total is not monotone, and empty cells make convergence slow, so tensors with empty cells were often left impure, silently. Withis_randomized=Falsethe same inputs purify to about 1e-16.Change
When the order is random, a sweep that fails to shrink the total now ends the loop only once the total has dropped to floating point noise, defined as 1e-12 of the first sweep. Otherwise the loop continues until 20 sweeps in a row fail to set a new minimum, which also guarantees that it terminates.
is_randomized=False) keeps the old exit condition and is unchanged.PurifyNormalizedMulticlass) had the same exit condition and gets the same change. I confirmed the multiclass case fails on the released library too.IsPurifySweepingDone, used by both loops.I picked the exit rule by simulating the sweep loop in Python on 5x6, 3x3x3, 4x5x6, 8x8x8, 32x32 and 10x10 tensors:
Evidence
Before and after on 100 random tensors each,
tolerance=0,is_randomized=True, worst weighted row or column sum:The "before" numbers are from the released 0.7.8 wheel. The "after" numbers are from a build of this branch.
Tests added:
PurifyTest.cpp: two cases (single class and multiclass) with 50 pseudo random 5x6 tensors each, 60% empty cells, zero tolerance. They check the weighted row and column sums directly becauseMeasureImpurityreturns NaN for a row or column with no weight. Both fail on the originalPurify.cpp(50 and 126 failed checks) and pass with this change.test_purify.py: two cases (3 tensor shapes, and a multiclass shape) with randomized order and empty cells. Both fail against the released 0.7.8 wheel and pass with this change.Checks run, Windows 11:
shared/libebm/tests, 348 tests): all pass.python/interpret-core/tests/utils: 225 passed, 9 skipped. I excludedtest_measure_interactions.py, which needs thedashpackage.ExplainableBoostingClassifierfit withpurify_resultenabled gives the same accuracy and the same purity on the original and the fixed library, in a similar time (5.4 s and 5.2 s).clang-formaton the changed C++ files andruff format --checkon the changed Python file are clean. Theclang-formatI had is version 12, not 16.Limits
Objective.hpp. I built the library and the tests with clang (via theziglangpackage) for x86_64 Windows, CPU compute unit only, with the same flags asbuild.sh(-std=c++11 -O3) andlibebm_exports.def. The AVX2 and AVX-512 units, the MSVC build, Linux, macOS, and the R package were not built or run here.ebminteraction tensors in my end-to-end check were already pure, so that check shows no change for them, not that the fix helps in training.purify_resultis off by default, as the issue notes.